/**
 * Copyright 2021 Inc.
 **/
package com.myz.rabbitmq.common.listener;

import com.myz.rabbitmq.common.config.RabbitConfig;
import com.myz.rabbitmq.common.config.RabbitMqConstant;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;

/**
 * @author maoyz0621 on 2021/6/8
 * @version v1.0
 */
@RabbitListener(bindings = {@QueueBinding(
        value = @Queue(value = RabbitMqConstant.QueueDef.FIRST_QUEUE, autoDelete = "false", durable = "true"),
        exchange = @Exchange(name = RabbitMqConstant.ExchangeDef.CONTRACT_DIRECT, durable = "true", type = ExchangeTypes.FANOUT, ignoreDeclarationExceptions = "true"),
        key = "queue_one_key")
})
@Component
public class OrderMessageListener {

    private static final Logger log = LoggerFactory.getLogger(RabbitConfig.class);

    @RabbitHandler
    public void handleMessage(@Payload Object msg, @Headers Map<String, Object> headers, Message message, Channel channel) throws IOException {
        log.info("OrderMessageListener handleMessage, body={}, exchange={}, deliveryTag={}, routingKe{}, queue={}\r\n",
                msg, message.getMessageProperties().getReceivedExchange(), message.getMessageProperties().getDeliveryTag(), message.getMessageProperties().getReceivedRoutingKey(), message.getMessageProperties().getConsumerQueue());
        try {

            // todo

            // 表示成功确认，使用此回执方法后，消息会被rabbitmq broker 删除
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            if (message.getMessageProperties().getRedelivered()) {

                log.error("消息已重复处理失败,拒绝再次接收...");

                // 拒绝消息，与basicNack区别在于不能进行批量操作，其他用法很相似。
                // deliveryTag：表示消息投递序号
                // requeue：值为 true 消息将重新入队列
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            } else {
                log.error("消息即将再次返回队列处理...");
                // 表示失败确认，一般在消费消息业务异常时用到此方法，可以将消息重新投递入队列。
                // deliveryTag：表示消息投递序号。
                // multiple：是否批量确认。
                // requeue：值为 true 消息将重新入队列。
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            }

        }
    }
}